import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults } from "axios";

import axios from "axios";

import { FileDownloader } from "./modules/downloader";
import { InterceptorManager } from "./modules/interceptor";
import { FileUploader } from "./modules/uploader";
import type { RequestClientOptions } from "./types";
import { merge } from "@/utils/merge";
import { bindMethods } from "@/utils";

class RequestClient {
	private readonly instance: AxiosInstance;

	public addRequestInterceptor: InterceptorManager["addRequestInterceptor"];
	public addResponseInterceptor: InterceptorManager["addResponseInterceptor"];

	public download: FileDownloader["download"];
	// 是否正在刷新token
	public isRefreshing = false;
	// 刷新token队列
	public refreshTokenQueue: ((token: string) => void)[] = [];
	public upload: FileUploader["upload"];

	/**
	 * 构造函数，用于创建Axios实例
	 * @param options - Axios请求配置，可选
	 */
	constructor(options: RequestClientOptions = {}) {
		// 合并默认配置和传入的配置
		const defaultConfig: CreateAxiosDefaults = {
			headers: {
				"Content-Type": "application/json;charset=utf-8",
			},
			// 默认超时时间
			timeout: 10_000,
		};
		const { ...axiosConfig } = options;
		const requestConfig = merge(axiosConfig, defaultConfig);
		this.instance = axios.create(requestConfig);

		bindMethods(this);

		// 实例化拦截器管理器
		const interceptorManager = new InterceptorManager(this.instance);
		this.addRequestInterceptor = interceptorManager.addRequestInterceptor.bind(interceptorManager);
		this.addResponseInterceptor = interceptorManager.addResponseInterceptor.bind(interceptorManager);

		// 实例化文件上传器
		const fileUploader = new FileUploader(this);
		this.upload = fileUploader.upload.bind(fileUploader);
		// 实例化文件下载器
		const fileDownloader = new FileDownloader(this);
		this.download = fileDownloader.download.bind(fileDownloader);
	}

	/**
	 * DELETE请求方法
	 */
	public delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
		return this.request<T>(url, { ...config, method: "DELETE" });
	}

	/**
	 * GET请求方法
	 */
	public get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
		return this.request<T>(url, { ...config, method: "GET" });
	}

	/**
	 * POST请求方法
	 */
	public post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
		return this.request<T>(url, { ...config, data, method: "POST" });
	}

	/**
	 * PUT请求方法
	 */
	public put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
		return this.request<T>(url, { ...config, data, method: "PUT" });
	}

	/**
	 * 通用的请求方法
	 */
	public async request<T>(url: string, config: AxiosRequestConfig): Promise<T> {
		try {
			const response: AxiosResponse<T> = await this.instance({
				url,
				...config,
			});
			return response as T;
		} catch (error: any) {
			throw error.response ? error.response.data : error;
		}
	}
}

export { RequestClient };
